package game.leon.seawar.bai;

import org.apache.log4j.Logger;

/**
 * User: BianP
 * Date: 11-12-30
 * AI系统, 用来自动决策
 * 1. 规则系统
 * 2. 概率
 */
public class AI {
    private Logger logger = Logger.getLogger(getClass());
    // 一个条件判断
    static interface Cond {
        int test(State state);
    }
    // 一个逻辑分支
    class Case {
        int value;
        Node node;
        public Case(int value, Cond cond) { 
            this.value = value;
            this.node = new Node(cond);
        }
    }
    // 逻辑分支的判断条件, 是一颗树
    // 需要and分支全部为真
    // 活着or分支一项为真
    class Node {
        Node orBranch;
        Node andBranch;
        Cond cond;
        public Node(Cond cond) {
            this.cond = cond;
        }
        public int test(State state) {
            // 只能有一种情况
            assert orBranch == null || andBranch == null;
            int r = cond.test(state);
            logger.info(String.format("[deduce] \t => %d", r));
            if (orBranch != null) {
                return or(r, orBranch.test(state));
            } else if (andBranch != null) {
                return and(r, andBranch.test(state));
            }
            return r;
        }
        public Node addAnd(Node node) {
            node.andBranch = andBranch;
            andBranch = node;
            return this;
        }
        public Node addAnd(Cond cond) {
            return this.addAnd(new Node(cond));
        }
        public Node addOr(Node node) {
            node.orBranch = orBranch;
            orBranch = node;
            return this;
        }
        public Node addOr(Cond cond) {
            return this.addOr(new Node(cond));
        }
    }
    //
    // 常量区
    //
    static interface Def {
        // 条件状态定义
        int IDLE = 0;

        //---------------------------------------------------------------
        // 行动类型
        //---------------------------------------------------------------
        // X动作判断
        int DEAD = 1;       // 死亡
        int ATTACK = 2;     // 进攻
        int DEFEND = 3;     // 防御
        int ACTION_MAJOR = 3; // 接下来的中间状态
        int READY_FIGHT = 4;      // 可以出手
        int ACTION_DONE = 10;

        //---------------------------------------------------------------
        // 选择目标, 技能
        //---------------------------------------------------------------
        int FIST = 1;   // 近身攻击
        int GUN = 2;    // 远程攻击
        int ATTACK_MAJOR = 2; //
        int TARGET_ALIVE = 3;   // 对手活着
        int IS_ENERMY = 4;      // 是敌人, 不是队友
        int NO_COVER = 5;       // 没有掩护
        int ATTACK_DONE = 10;

        // BOOLEAN LOGIC
        int NONE = 0;
        int TRUE = 1;
        int FALSE = -1;
    }
    //---------------------------------------------------------------------------------------
    //
    // 某个case是否成立, 这个简单的
    //
    class CaseCond implements Cond {
        private int val;
        CaseCond(int val) {
            this.val = val;
        }
        @Override
        public int test(State state) {
            return cond(state, val);
        }
    }
    public static boolean bool(int val) {
        return val > 0;
    }
    public static int bool(boolean val) {
        return val ? Def.TRUE : Def.FALSE;
    }
    public static int not(int a) {
        return bool(!(a > 0));
    }
    public static int and(int a, int b) {
        return bool(bool(a) && bool(b));
    }
    public static int or(int a, int b) {
        return bool(bool(a) || bool(b));
    }
    //---------------------------------------------------------------------------------------
    private int cond(State state, int cond) {
        Case c = cases[cond];
        if (c != null) {
            int result = state.cases[cond]; 
            if (result != Def.NONE) {
                logger.info(String.format("[cached] %d => %d", cond, result));
                return result;
            }
            logger.info(String.format("[deduce] %d =>", cond));
            result = c.node.test(state);
            state.cases[cond] = result;
            return result;
        }
        return Def.NONE;
    }
    private int major; // status lower than major is finish
    private int done;
    private Case[] cases;
    public AI(int major, int done) {
        this.major = major;
        this.done = done;
        this.cases = new Case[done];
    }
    
    // register action decide roles
    private void initActionAI() {
        // DEAD
        Case deadCase = new Case(Def.DEAD, new Cond() {
            @Override
            public int test(State state) {
                return bool(state.hp <= 0);
            }
        });
        register(deadCase);
        // ATTACK
        Case attackCase = new Case(Def.ATTACK, new CaseCond(Def.READY_FIGHT));
        register(attackCase);
        attackCase.node.addAnd(new Cond() {
            @Override
            public int test(State state) {
                return bool(state.cmd == State.Def.CMD_ATTACK);
            }
        });
        // READY_FIGHT
        Case readyFightCase = new Case(Def.READY_FIGHT, new Cond() {
            @Override
            public int test(State state) {
                return bool(state.status != State.Def.STATUS_DEAD &&
                        state.status != State.Def.STATUS_FAINT);
            }
        });
        register(readyFightCase);
        // DEFEND
        Case defendCase = new Case(Def.DEFEND, new Cond() {
            @Override
            public int test(State state) {
                return bool(state.cmd == State.Def.CMD_DEFEND);
            }
        });
        register(defendCase);
    }
    // 技能类型的判断
    private static class SkillTypeCond implements Cond {
        private int st;
        public SkillTypeCond(int st) {
            this.st = st;
        }
        @Override
        public int test(State state) {
            return bool(state.skill != null && state.skill.type == st);
        }
    }
    private static class EnermyCond implements Cond {
        @Override
        public int test(State state) {
            return bool((state.team % 2) != (state.target.team % 2));
        }
    }
    private static class NoCoverCond implements Cond {
        private boolean firstRowOrNoCover(State state, State target) {
            if (target.row == 1) return true;
            State cover = findCover(state, target);
            return cover == null || cover.hp <= 0;
        }
        @Override
        public int test(State state) {
            // 在第一排, 或者没有前排, 或者前排的人已死
            return bool(firstRowOrNoCover(state, state) && firstRowOrNoCover(state, state.target));
        }
    }
    private static class FriendCond implements Cond {
        @Override
        public int test(State state) {
            return bool(state.id != state.target.id &&
                    state.team == state.target.team);
        }
    }
    // 找当前目标的掩护者
    private static State findCover(State state, State target) {
        assert target.row == 2;
        for(int i = 0; i < state.targets.length; ++i) {
            State cover = state.targets[i];
            if (cover == null ||
                    state.id == cover.id ||             // 自己跳过
                    target.id == cover.id ||            // 目标跳过
                    target.team != cover.team           // 非目标队友跳过
                    ) continue;
            // 如果是在同列前排
            if (cover.col == state.target.col && cover.row == 1)
                return cover;
        }
        return null;
    }
    // 选择打击目标和技能
    private void initAttackAI() {
        // target must be alive
        Case targetAliveCase = new Case(Def.TARGET_ALIVE, new Cond() {
            @Override
            public int test(State state) {
                return bool(state.target != null && state.target.hp > 0);
            }
        });
        register(targetAliveCase);
        // is enermy
        Case isEnerMyCase = new Case(Def.IS_ENERMY, new EnermyCond());
        register(isEnerMyCase);
        // no cover
        Case noCoverCase = new Case(Def.NO_COVER, new NoCoverCond());
        register(noCoverCase);
        // fist
        Case fistCase = new Case(Def.FIST, new CaseCond(Def.TARGET_ALIVE));
        register(fistCase);
        // 越优先的条件, 放到越后面, 越是提前执行
        // 要求无遮挡
        fistCase.node.addAnd(new CaseCond(Def.NO_COVER));
        // 必须是敌人
        fistCase.node.addAnd(new CaseCond(Def.IS_ENERMY));
        // 技能类型
        fistCase.node.addAnd(new SkillTypeCond(Skill.Def.ST_FIST));
        // gun
        Case gunCase = new Case(Def.GUN, new CaseCond(Def.TARGET_ALIVE));
        register(gunCase);
        gunCase.node.addAnd(new CaseCond(Def.IS_ENERMY));
        gunCase.node.addAnd(new Node(new SkillTypeCond(Skill.Def.ST_GUN)));
    }
    
    private void register(Case c) {
        assert cases[c.value] == null;
        cases[c.value] = c;
    }

    public int exec(State state) {
        state.cases = new int[this.done];
        for(int cond = 1; cond <= this.major; ++cond) {
            int result = cond(state, cond);
            if (result == Def.TRUE) {
                logger.info(String.format("[matched] %d", cond));
                return cond;
            }
        }
        return Def.IDLE;
    }
    
    public static AI createActionAI() {
        AI ai = new AI(Def.ACTION_MAJOR, Def.ACTION_DONE);
        ai.initActionAI();
        return ai;
    }
    public static AI createAttackAI() {
        AI ai = new AI(Def.ATTACK_MAJOR, Def.ATTACK_DONE);
        ai.initAttackAI();
        return ai;
    }
}
